#!/usr/bin/env python3
# coding: utf-8
import argparse
import time
import typing
import os
import atexit
from multiprocessing import Process, Pipe

import py_trees
import py_trees.console as console


def description() -> str:
    """
    Print description and usage information about the program.

    Returns:
       the program description string
    """
    content = "Demonstrates a typical day in the life of a behaviour.\n\n"
    content += (
        "This behaviour will count from 1 to 3 and then reset and repeat. As it does\n"
    )
    content += "so, it logs and displays the methods as they are called - construction, setup,\n"
    content += "initialisation, ticking and termination.\n"
    if py_trees.console.has_colours:
        banner_line = console.green + "*" * 79 + "\n" + console.reset
        s = banner_line
        s += (
            console.bold_white + "Behaviour Lifecycle".center(79) + "\n" + console.reset
        )
        s += banner_line
        s += "\n"
        s += content
        s += "\n"
        s += banner_line
    else:
        s = content
    return s


# 尾声
def epilog() -> typing.Optional[str]:
    if py_trees.console.has_colours:
        return (
            console.cyan
            + "And his noodly appendage reached forth to tickle the blessed...\n"
            + console.reset
        )
    else:
        return None


def command_line_argument_parser() -> argparse.ArgumentParser:
    return argparse.ArgumentParser(
        description=description(),
        epilog=epilog(),
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )


def child_Process_update(pipe, ppid):
    percentage_complete = 0
    while True:
        if pipe.poll():
            cmd = pipe.recv()
            if cmd == "stop":
                break
            elif cmd == "start":
                percentage_complete = 0
            elif cmd == "update":
                percentage_complete += 10
                min(percentage_complete, 100)
                pipe.send(percentage_complete)

        # 检查父进程是否还存在
        try:
            os.kill(ppid, 0)
        except OSError:
            break

        time.sleep(1)
    pipe.close()
    print("child process exit")


class Counter(py_trees.behaviour.Behaviour):
    def __init__(self, name: str = "Counter"):
        """构造"""
        super().__init__(name)
        self.logger.debug("%s.__init__()" % (self.__class__.__name__))
        # 注册退出处理函数
        # atexit.register(self.cleanup)

    def setup(self, **kargs: typing.Any) -> None:
        """初始化"""
        self.logger.debug("%s.setup()" % (self.__class__.__name__))
        self.parent_pip, self.child_pip = Pipe()

    def initialise(self) -> None:
        """重置值"""
        self.logger.debug("%s.initialise()" % (self.__class__.__name__))
        self.child_process = Process(
            target=child_Process_update, args=(self.child_pip, os.getpid())
        )
        self.child_process.start()
        self.parent_pip.send("start")

    def update(self) -> py_trees.common.Status:
        """更新"""
        self.logger.debug("%s.update()" % (self.__class__.__name__))

        new_status = py_trees.common.Status.RUNNING
        self.parent_pip.send("update")
        percentage_complete = self.parent_pip.recv()
        if percentage_complete == 100:
            self.feedback_message = "processing finished"
            new_status = py_trees.common.Status.SUCCESS
        else:
            self.feedback_message = f"processing {percentage_complete}%"

        self.logger.debug(
            "%s.update()[%s->%s][%s]"
            % (self.__class__.__name__, self.status, new_status, self.feedback_message)
        )
        return new_status

    def terminate(self, new_status: py_trees.common.Status) -> None:
        """终止"""

        # 更安全的终止子进程
        self.cleanup()

        self.logger.debug(
            "%s.terminate()[%s->%s]"
            % (self.__class__.__name__, self.status, new_status)
        )

    def cleanup(self):
        """确保子进程被终止"""
        if hasattr(self, "child_process") and self.child_process.is_alive():
            try:
                self.parent_pip.send("stop")
                self.child_process.join(timeout=1)
                if self.child_process.is_alive():
                    self.child_process.terminate()
                    self.child_process.join()
            except (EOFError, OSError, AttributeError):
                if self.child_process.is_alive():
                    self.child_process.terminate()
                    self.child_process.join()

    def __del__(self):
        """析构函数中也进行清理"""
        self.cleanup()


def main() -> None:
    """Entry point for the demo script."""
    command_line_argument_parser().parse_args()
    print(description())
    py_trees.logging.level = py_trees.logging.Level.DEBUG

    counter = Counter()
    counter.setup()
    try:
        for _unused_i in range(0, 12):
            counter.tick_once()
            time.sleep(0.5)
        print("\n")
    except KeyboardInterrupt:
        print("")
        pass


if __name__ == "__main__":
    main()


""" 
生命周期
# 1.初始化
__init__
setup
initialise

# 2.运行
tick --> update
...
tick --> update

# 3.终止
当Status为Success或Failure时 --> 调用terminate
stop --> terminate

"""
